#!/bin/env python2.5.1
import Dingo.API as api #Imports the Dingo API
import Dingo.models.OneHopP2P as P2P 
import Dingo.models.FloodRouter as FloodRouter
import random, Image
import Hi

#Static variables
NUMSENSOR = 50     #The number of sensor nodes
scatterNodes = 256  #Topography area
sendDelay = 1       #Approx. delay between different nodes transmission
tdist = 1000        #Radio transmission range
c_LIFE = 50         #Time for each cluser round
STIME = 15          #Time a CH waits before it creates and sends a TDMA schedule


class TheSimulation(api.Simulation):    #Main class Required to run as a sensor module
    def __init__(self, graph):          #Initialise the program
        ether = api.Ether(self)         #Setup the transmission medium
        ether.RF_radius = tdist         #Setuup the radio radius
        im = Image.open("/home/snim2/Desktop/working/dingo/dingo-wsn/trunk/test/leach-test/" + "landsc.png")   #Get map data
        BSsensor = Ssensor(graph, ether, -1, NUMSENSOR)     #Create sink node
        sensors = [aSensor(graph,ether,i,im) for i in xrange(NUMSENSOR)]        #Create sensor nodes
        sensors.append(BSsensor)        #Add the sink node the network
        api.Simulation.__init__(self, sensors, graph)       #Initialise the simulation
        graph.addBackground("/leach-test/landsc.png")
    def run(self):  #Must have to Run the simulation
        super(TheSimulation, self).run()    #Run the Simulation


class Ssensor(api.Sensor): #Define the behaviour of the sink object
    def __init__(self,graph,ether,i, NUMSENSOR): 
        #Define the sink location
        x = scatterNodes/2
        y = scatterNodes/2

        self.state = "Sink" #Initial sink state
        self.points = []    #Store sink data
        self.Routing = Hi.sinkRouting(self, NUMSENSOR)  #Define routing protocol

        #Create A List of Tasks to be Preformed
        taskList = [initialize(self), receiveTask(self)]
        #Initilise the Scheduler for this sensor
        #(<self>,<graph>,<Sensor><(X,Y)coords>,<Sensor Color>,<Scheduler Tasks>,<Ether>
        api.Sensor.__init__(self,"Sink[%d]" %i, (x,y),api.SensorColor.Red, api.Scheduler(taskList,-1),ether,P2P.OneHopP2P(),5)
        

class aSensor(api.Sensor): #Define the behaviour of sensor nodes
    def __init__(self,graph,ether,i,Im): 
        #Define the sensor node location
        x = random.randrange(0,scatterNodes)
        y = random.randrange(0,scatterNodes)

        z = Im.getpixel((x,y))[0]   #Get sensor reading

        #---------Start Editing---------
        self.number = i         #Set node ID
        self.Routing = Hi.sensorRouting(self)        #Define routing protocol
        self.state = "Waiting"  #Set initial state
        self.isCH = False       #Flag to indicate whether node is CH or not
        self.lastNode = '-'     #Next node in the path to the CH
        self.myCH = '-'         #Store nodes current CH
        self.timestamp = Hi.timeStamp()     #Used to measure cluster round life
        self.scheduleTime = Hi.timeStamp()  #Used to time TDMA creation
        self.tdma = True        #False after TDMA is created
        self.seenADV_SCH = []   #Remember all seen ADV_SCH messages
        self.checktdma = False  #If true then check if time to create TDMA
        self.s_Path = '-'       #The next node in the path to sink
        self.data = (x,y,z)     #Data packet payload
        self.members = []       #When a node is CH,it stores nodes that belong to this cluster
        self.points = []        #Node buffer
        self.AGdata = []        #Used for data aggregation
        self.r = 0              #Number of rounds
        self.g = -1             #Number of round the node was CH for the last time

        #---------End Editing---------

        #Create A List of Tasks to be Preformed
        taskList = [receiveTask(self), checkTask(self)]
        #Initilise the Scheduler for this sensor
        #(<self>,<graph>,<Sensor><(X,Y)coords>,<Sensor Color>,<Scheduler Tasks>,<Ether>
        api.Sensor.__init__(self,"Sensor[%d]" %i, (x,y),api.SensorColor.White, api.Scheduler(taskList,-1),ether,P2P.OneHopP2P(),5)
        

class receiveTask(api.Task): #Define node behaviour upon receiving a packet
    def __init__(self, sensor):
        # self, priority, repetitions, ref-to-sensor
        api.Task.__init__(self, 0, 0, sensor)

    def task(self):
        while not self.sensor.recv_q.empty():
            themsg = self.sensor.recv_q.get()
            self.sensor.Routing.receiveTask(themsg)

class checkTask(api.Task):
    def __init__(self, sensor):
        api.Task.__init__(self, 0, 0, sensor)

    def task(self):
        if self.sensor.timestamp.diff(Hi.timeStamp()) >= c_LIFE:
            if self.sensor.isCH:
                api.Sleep(2) #Very important to create a kind of synchronization in the network
                self.sensor.Routing.checkExpires()
            else:
                self.sensor.Routing.checkExpires()

        if self.sensor.isCH and self.sensor.checktdma and self.sensor.scheduleTime.diff(Hi.timeStamp()) >= STIME and self.sensor.tdma:
            self.sensor.Routing.createTDMA()

        if len(self.sensor.AGdata) > 0 and len(self.sensor.AGdata) == len(self.sensor.members):
            self.sensor.Routing.emptyAGdata()


class initialize(api.Task):
    def __init__(self, sensor):
        api.Task.__init__(self, 0, 0, sensor)

    def task(self):
        if self.sensor.state == "Sink":
            self.sensor.Routing.StartUp()